/*
 * @Author: liusheng
 * @Date: 2022-07-02 19:14:31
 * @LastEditors: liusheng
 * @LastEditTime: 2022-07-02 19:18:10
 * @Description: 剑指 Offer II 093. 最长斐波那契数列
 * email:liusheng613@126.com
 * Copyright (c) 2022 by liusheng/liusheng, All Rights Reserved. 
 * 
 剑指 Offer II 093. 最长斐波那契数列
如果序列 X_1, X_2, ..., X_n 满足下列条件，就说它是 斐波那契式 的：

n >= 3
对于所有 i + 2 <= n，都有 X_i + X_{i+1} = X_{i+2}
给定一个严格递增的正整数数组形成序列 arr ，找到 arr 中最长的斐波那契式的子序列的长度。如果一个不存在，返回  0 。

（回想一下，子序列是从原序列  arr 中派生出来的，它从 arr 中删掉任意数量的元素（也可以不删），而不改变其余元素的顺序。例如， [3, 5, 8] 是 [3, 4, 5, 6, 7, 8] 的一个子序列）

 

示例 1：

输入: arr = [1,2,3,4,5,6,7,8]
输出: 5
解释: 最长的斐波那契式子序列为 [1,2,3,5,8] 。
示例 2：

输入: arr = [1,3,7,11,12,14,18]
输出: 3
解释: 最长的斐波那契式子序列有 [1,11,12]、[3,11,14] 以及 [7,11,18] 。
 

提示：

3 <= arr.length <= 1000
1 <= arr[i] < arr[i + 1] <= 10^9

 

注意：本题与主站 873 题相同： https://leetcode-cn.com/problems/length-of-longest-fibonacci-subsequence/

通过次数10,374  提交次数17,597
 */

#include "header.h"

/*
Algorithm

Let longest[i, j] be the longest path ending in [i, j]. 
Then longest[j, k] = longest[i, j] + 1 if (i, j) and (j, k) are connected. 
Since i is uniquely determined as A.index(A[k] - A[j]), this is efficient: 
we check for each j < k what i is potentially, and update longest[j, k] accordingly.
*/
class Solution {
public:
    int lenLongestFibSubseq(vector<int>& arr) {
        int n = arr.size();
        vector<vector<int>> dp(n,vector<int>(n,2));

        unordered_map<int,int> numIndexMap;
        for (int i = 0; i < n; ++i)
        {
            numIndexMap[arr[i]] = i;
        }

        int maxLen = 2;
        for (int i = 2; i < n; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                int temp = arr[i] - arr[j];
                if (numIndexMap.count(temp) && numIndexMap[temp] < j)
                {
                    dp[i][j] = dp[j][numIndexMap[temp]] + 1;
                    maxLen = max(maxLen,dp[i][j]);
                }
                else
                {
                    dp[i][j] = 2;
                }
            }
        }

        return maxLen == 2 ? 0 : maxLen;
    }
};